package com.xinan.tool.aoi.util;

import cn.hutool.core.map.MapUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 百度
 * 墨卡托坐标与经纬度坐标转换
 *
 * @author fc.w
 * @date 2017/11/30
 */
public class BaiduMokatorToLngLat {

    private static Double EARTHRADIUS = 6370996.81;
    private static Double[] MCBAND = {12890594.86, 8362377.87, 5591021d, 3481989.83, 1678043.12, 0d};
    private static Double[] LLBAND = {75d, 60d, 45d, 30d, 15d, 0d};
    private static Double[][] MC2LL = {{1.410526172116255e-8, 0.00000898305509648872, -1.9939833816331, 200.9824383106796, -187.2403703815547, 91.6087516669843, -23.38765649603339, 2.57121317296198, -0.03801003308653, 17337981.2}, {-7.435856389565537e-9, 0.000008983055097726239, -0.78625201886289, 96.32687599759846, -1.85204757529826, -59.36935905485877, 47.40033549296737, -16.50741931063887, 2.28786674699375, 10260144.86}, {-3.030883460898826e-8, 0.00000898305509983578, 0.30071316287616, 59.74293618442277, 7.357984074871, -25.38371002664745, 13.45380521110908, -3.29883767235584, 0.32710905363475, 6856817.37}, {-1.981981304930552e-8, 0.000008983055099779535, 0.03278182852591, 40.31678527705744, 0.65659298677277, -4.44255534477492, 0.85341911805263, 0.12923347998204, -0.04625736007561, 4482777.06}, {3.09191371068437e-9, 0.000008983055096812155, 0.00006995724062, 23.10934304144901, -0.00023663490511, -0.6321817810242, -0.00663494467273, 0.03430082397953, -0.00466043876332, 2555164.4}, {2.890871144776878e-9, 0.000008983055095805407, -3.068298e-8, 7.47137025468032, -0.00000353937994, -0.02145144861037, -0.00001234426596, 0.00010322952773, -0.00000323890364, 826088.5}};
    private static Double[][] LL2MC = {{-0.0015702102444, 111320.7020616939, 1704480524535203d, -10338987376042340d, 26112667856603880d, -35149669176653700d, 26595700718403920d, -10725012454188240d, 1800819912950474d, 82.5}, {0.0008277824516172526, 111320.7020463578, 647795574.6671607, -4082003173.641316, 10774905663.51142, -15171875531.51559, 12053065338.62167, -5124939663.577472, 913311935.9512032, 67.5}, {0.00337398766765, 111320.7020202162, 4481351.045890365, -23393751.19931662, 79682215.47186455, -115964993.2797253, 97236711.15602145, -43661946.33752821, 8477230.501135234, 52.5}, {0.00220636496208, 111320.7020209128, 51751.86112841131, 3796837.749470245, 992013.7397791013, -1221952.21711287, 1340652.697009075, -620943.6990984312, 144416.9293806241, 37.5}, {-0.0003441963504368392, 111320.7020576856, 278.2353980772752, 2485758.690035394, 6070.750963243378, 54821.18345352118, 9540.606633304236, -2710.55326746645, 1405.483844121726, 22.5}, {-0.0003218135878613132, 111320.7020701615, 0.00369383431289, 823725.6402795718, 0.46104986909093, 2351.343141331292, 1.58060784298199, 8.77738589078284, 0.37238884252424, 7.45}};

    public static void main(String[] args) {
        Map<String, Double> locationPoint = convertMC2LL(13372307.47, 3514145.00);
        locationPoint = convertLL2MC(locationPoint.get("lng"), locationPoint.get("lat"));
        System.out.println(locationPoint);

//        String geo = "4|13217752.484188,3747707.501811;13218178.787006,3747927.843797|1-13218177.2959396,3747786.5648262,13218178.7870056,3747744.5298201,13218178.3373703,3747739.7744437,13218176.7731059,3747735.8122181,13218173.6035060,3747732.6470467,13218146.8247333,3747715.9171073,13218138.4346426,3747711.9064486,13218128.2608917,3747709.2709057,13218117.9099520,3747708.6250556,13218073.5640441,3747712.7191450,13218066.7931901,3747712.8574033,13218064.5510899,3747712.9034527,13218055.9833378,3747711.9863223,13218042.8624457,3747708.9670505,13218031.5272698,3747707.5018112,13217970.7479462,3747708.8098547,13217967.3122995,3747709.8370376,13217964.9489017,3747712.4226717,13217964.1487247,3747716.6141634,13217963.7308251,3747754.5848277,13217962.7968839,3747758.9868304,13217960.2995925,3747761.6261811,13217956.8638997,3747762.7059910,13217854.2966557,3747767.3232578,13217850.2337389,3747766.3736173,13217847.8209848,3747763.4189513,13217847.0589984,3747759.2435818,13217846.8505827,3747719.2920170,13217845.9995583,3747715.4836964,13217843.3638713,3747712.9499189,13217842.3928294,3747712.8036231,13217839.4350516,3747712.3652741,13217774.2264489,3747718.8366082,13217761.0453051,3747720.1526383,13217755.6449625,3747722.9349041,13217752.7470661,3747728.6166836,13217752.4841877,3747735.3135968,13217770.0918468,3747879.0267738,13217772.2847021,3747886.1660015,13217775.9947224,3747892.1896103,13217780.4625983,3747896.6880759,13217808.2428621,3747912.1665290,13217828.0754624,3747927.8437973,13218005.6185446,3747914.2062693,13218170.3454938,3747913.4062102,13218174.9834748,3747911.4870830,13218175.2076384,3747891.2808905,13218173.7485980,3747878.4446062,13218173.7440966,3747878.3884237,13218173.0630676,3747863.4842886,13218173.0630543,3747863.4659852,13218172.6029086,3747844.1163024,13218172.6028801,3747844.0770809,13218173.0350703,3747825.0315486,13218173.0383777,3747824.9792270,13218173.1600160,3747823.5623679,13218173.1600141,3747823.5597531,13218174.1222932,3747812.6877881,13218174.3656334,3747809.9508199,13218174.3689589,3747809.9233386,13218177.1637749,3747787.3045343,13218177.1704315,3747787.2574163,13218177.2959396,3747786.5648262";
        String geo = "4|13216656.387800,3744999.660450;13226333.389300,3758369.794880|1-13226333.4,3757210.6,13226332.2,3757227.1,13226320.0,3757241.3,13226272.5,3757266.4,13226136.5,3757348.2,13226069.0,3757396.1,13226045.5,3757444.3,13226004.0,3757543.0,13225982.6,3757605.5,13225979.9,3757660.4,13225980.1,3757774.9,13225961.7,3757878.1,13225941.8,3757900.0,13225918.6,3757908.5,13225881.3,3757903.8,13225825.4,3757884.6,13225796.9,3757871.2,13225754.1,3757854.2,13225706.1,3757813.0,13225645.3,3757725.4,13225599.7,3757656.7,13225543.8,3757517.4,13225347.1,3757254.0,13225291.4,3757216.9,13225270.6,3757215.6,13225219.0,3757215.8,13225134.3,3757225.5,13225068.5,3757228.6,13224989.4,3757247.1,13224927.8,3757269.1,13224867.2,3757295.3,13224813.2,3757329.5,13224768.9,3757378.1,13224757.7,3757398.8,13224743.0,3757462.3,13224724.8,3757544.4,13224708.8,3757626.5,13224687.5,3757678.9,13224658.9,3757701.4,13224606.9,3757751.9,13224570.7,3757756.7,13224558.7,3757752.0,13224527.2,3757719.4,13224477.2,3757663.3,13224360.2,3757485.6,13224268.5,3757319.5,13224163.5,3757156.3,13224100.5,3757099.6,13224075.5,3757083.5,13224018.7,3757066.7,13223957.4,3757054.0,13223898.3,3757050.2,13223845.8,3757052.0,13223819.5,3757063.3,13223768.8,3757094.9,13223681.8,3757160.5,13223627.8,3757208.5,13223607.9,3757225.5,13223600.2,3757238.5,13223602.2,3757264.9,13223618.5,3757281.8,13223668.6,3757313.1,13223768.6,3757389.6,13223863.4,3757450.7,13223997.2,3757546.7,13224063.7,3757595.8,13224081.0,3757619.3,13224108.9,3757677.3,13224103.1,3757718.4,13224096.2,3757760.1,13224034.3,3757835.4,13223043.5,3758103.2,13222370.8,3758271.0,13221974.3,3758369.8,13221599.2,3758128.1,13221205.7,3757771.7,13219358.8,3756032.5,13218888.3,3755569.1,13218634.8,3755154.4,13218299.3,3754681.7,13218019.2,3754180.2,13217787.9,3753737.5,13217629.7,3753582.4,13217784.3,3753405.9,13217825.5,3753196.6,13217860.7,3753037.9,13217883.9,3752909.5,13217885.7,3752880.3,13217879.2,3752778.0,13217867.8,3752632.7,13217853.3,3752485.8,13217840.3,3752337.4,13217828.1,3752182.9,13217819.7,3752113.7,13217791.9,3752034.6,13217761.1,3751955.4,13217725.7,3751865.5,13217678.2,3751752.1,13217651.4,3751664.6,13217633.6,3751595.4,13217627.5,3751520.9,13217621.5,3751466.9,13217622.0,3751432.6,13217619.2,3751397.0,13217616.5,3751362.0,13217617.0,3751327.3,13217614.7,3751291.9,13217613.5,3751255.5,13217610.8,3751222.4,13217615.0,3751150.5,13217621.8,3751070.1,13217645.1,3750925.2,13217662.1,3750822.1,13217670.7,3750749.5,13217680.1,3750638.3,13217689.4,3750503.3,13217688.6,3750363.0,13217684.8,3750252.0,13217675.2,3750105.4,13217668.8,3750049.0,13217660.9,3749961.0,13217651.1,3749898.2,13217617.5,3749679.3,13217597.3,3749539.4,13217586.4,3749433.2,13217574.6,3749321.1,13217565.8,3749246.7,13217555.8,3749162.2,13217528.8,3748976.0,13217507.1,3748903.1,13217495.5,3748824.7,13217491.8,3748772.6,13217477.5,3748678.6,13217463.2,3748617.0,13217430.1,3748487.5,13217392.0,3748362.3,13217360.8,3748258.4,13217341.0,3748200.9,13217297.9,3748092.3,13217248.0,3747977.7,13217231.3,3747935.3,13217179.2,3747821.4,13217126.4,3747774.0,13217076.8,3747666.5,13217031.9,3747580.3,13216998.8,3747515.5,13216959.7,3747437.7,13216918.6,3747361.3,13216860.8,3747251.1,13216819.8,3747169.4,13216756.7,3747049.6,13216678.7,3746904.3,13216660.5,3746862.3,13216657.5,3746855.4,13216656.4,3746850.8,13216660.7,3746847.0,13216750.4,3746795.1,13216828.8,3746750.2,13216928.9,3746696.4,13217184.8,3746614.2,13217258.5,3746576.5,13217324.0,3746549.3,13217439.5,3746458.7,13217539.0,3746411.9,13217542.6,3746409.6,13217543.1,3746405.7,13217537.7,3746401.1,13217521.8,3746393.8,13217462.5,3746363.6,13217411.6,3746341.6,13217288.2,3746284.7,13217242.4,3746257.3,13217200.4,3746227.9,13217161.7,3746188.6,13217151.7,3746180.2,13217116.2,3746122.8,13217047.3,3746007.8,13216982.3,3745882.9,13216923.7,3745780.3,13216862.8,3745666.2,13216800.7,3745549.1,13216753.9,3745467.6,13216753.2,3745463.4,13216754.8,3745460.7,13216866.0,3745391.4,13216905.0,3745366.1,13216944.3,3745348.6,13217017.6,3745314.2,13217143.0,3745253.8,13217205.6,3745227.3,13217229.8,3745219.1,13217247.3,3745214.1,13217351.1,3745185.1,13217491.3,3745144.2,13217569.8,3745118.6,13217695.9,3745091.9,13217806.9,3745068.3,13217912.0,3745044.4,13217987.6,3745025.2,13218131.0,3745013.2,13218245.6,3744999.7,13218248.3,3744999.8,13218251.4,3745000.5,13218251.7,3745003.5,13218252.7,3745014.4,13218254.0,3745049.7,13218262.7,3745133.9,13218270.3,3745263.1,13218272.1,3745355.8,13218273.5,3745444.1,13218282.1,3745506.4,13218289.2,3745610.7,13218295.7,3745685.3,13218300.8,3745754.0,13218307.2,3745888.6,13218310.7,3745996.7,13218323.0,3746159.8,13218325.3,3746273.9,13218332.3,3746380.0,13218332.3,3746382.7,13218333.5,3746384.3,13218341.1,3746385.8,13218446.4,3746385.3,13218583.6,3746387.0,13218691.7,3746387.0,13218817.1,3746385.8,13218994.0,3746384.7,13219063.5,3746384.0,13219123.0,3746381.7,13219173.2,3746373.8,13219289.2,3746350.7,13219402.2,3746324.0,13219556.0,3746293.3,13219619.4,3746279.1,13219661.1,3746271.4,13219683.5,3746271.7,13219751.3,3746276.1,13219868.4,3746282.9,13219947.7,3746286.8,13219974.7,3746284.3,13220005.6,3746278.1,13220110.6,3746254.1,13220460.3,3746176.3,13220518.2,3746164.7,13220581.3,3746160.2,13220705.4,3746145.8,13220801.6,3746135.3,13220887.6,3746124.8,13220907.5,3746122.6,13220916.1,3746122.9,13220922.2,3746127.3,13220989.5,3746193.0,13221132.3,3746301.8,13221449.0,3746542.8,13221594.7,3746651.3,13221629.5,3746670.8,13221692.2,3746708.7,13221698.7,3746714.6,13221801.3,3746775.9,13221854.1,3746806.7,13221944.4,3746841.6,13222079.5,3746881.2,13222117.6,3746890.8,13222147.5,3746892.2,13222178.3,3746891.6,13222254.3,3746885.8,13222397.4,3746876.1,13222741.5,3746851.1,13223153.8,3746817.5,13223416.9,3746797.1,13223689.7,3746776.5,13223879.1,3746761.2,13223848.6,3746824.9,13223853.7,3746932.9,13223851.0,3747345.8,13223850.5,3747627.1,13223850.4,3747853.8,13223851.3,3747998.7,13223852.2,3748136.7,13223850.5,3748294.2,13223853.6,3748441.2,13223854.6,3748643.4,13223853.9,3748781.8,13223855.3,3748835.1,13223855.3,3748838.2,13223866.6,3748854.6,13223877.6,3748871.9,13223883.9,3748890.4,13223886.9,3748904.7,13223888.3,3748957.8,13223885.0,3749010.1,13223880.9,3749036.5,13223873.0,3749052.4,13223861.4,3749067.1,13223857.8,3749072.0,13223856.5,3749081.3,13223856.3,3749136.4,13223849.5,3749849.8,13223851.5,3750632.4,13223850.5,3751081.8,13223848.4,3751817.7,13223848.8,3752243.6,13223843.7,3752490.3,13223834.6,3752769.2,13223827.9,3752886.3,13223824.1,3753039.0,13223825.0,3753193.2,13223825.2,3753207.8,13223842.4,3753315.2,13223845.8,3753353.4,13223978.0,3753307.8,13224049.1,3753279.6,13224116.5,3753245.9,13224227.9,3753194.9,13224395.3,3753111.1,13224553.3,3753036.1,13224623.9,3752999.9,13224726.7,3752947.9,13224827.0,3752897.6,13224928.8,3752839.4,13224992.4,3752810.9,13225004.7,3752805.0,13225011.3,3752804.6,13225015.8,3752807.8,13225021.6,3752817.5,13225041.1,3752854.4,13225043.8,3752858.7,13225056.5,3752861.5,13225089.7,3752862.9,13225168.8,3752857.9,13225256.1,3752847.7,13225302.0,3752846.4,13225314.7,3752855.5,13225328.0,3752868.3,13225343.9,3752890.8,13225366.5,3752941.9,13225367.1,3752949.6,13225366.4,3752959.9,13225355.7,3752982.9,13225347.3,3753002.0,13225324.6,3753032.8,13225301.3,3753067.5,13225296.2,3753083.9,13225295.9,3753104.7,13225305.0,3753144.1,13225306.1,3753151.0,13225304.1,3753158.2,13225296.3,3753168.5,13225268.7,3753183.2,13225224.8,3753213.2,13225214.5,3753227.3,13225208.6,3753243.4,13225208.5,3753254.6,13225215.5,3753283.5,13225221.5,3753295.1,13225231.0,3753304.5,13225245.6,3753310.4,13225303.0,3753320.5,13225358.8,3753333.9,13225375.6,3753343.4,13225405.1,3753364.9,13225432.2,3753391.8,13225447.6,3753402.4,13225474.4,3753412.6,13225556.4,3753440.2,13225558.6,3753447.1,13225558.4,3753459.0,13225555.9,3753480.6,13225549.8,3753507.0,13225509.6,3753601.5,13225482.5,3753673.5,13225482.1,3753682.2,13225486.6,3753690.3,13225494.2,3753700.9,13225506.1,3753709.0,13225527.2,3753716.7,13225574.8,3753730.8,13225579.9,3753736.3,13225579.3,3753750.0,13225566.3,3753831.9,13225567.0,3753841.0,13225575.7,3753850.0,13225688.3,3753933.4,13225814.1,3753969.5,13225807.3,3753991.4,13225816.0,3754008.0,13225824.7,3754019.1,13225865.1,3754046.3,13225932.5,3754122.2,13225946.4,3754169.1,13225958.2,3754206.6,13225961.7,3754241.2,13225960.6,3754252.8,13225953.4,3754263.0,13225881.2,3754333.8,13225792.6,3754418.6,13225732.6,3754490.6,13225633.0,3754703.4,13225563.8,3754831.1,13225514.0,3754992.2,13225498.3,3755031.5,13225505.7,3755190.0,13225536.6,3755305.8,13225572.1,3755389.2,13225659.8,3755524.4,13225764.9,3755707.0,13225822.7,3755882.3,13225855.3,3756063.6,13225873.5,3756182.5,13225911.6,3756347.8,13225926.5,3756454.7,13225931.9,3756495.9,13225958.9,3756604.0,13226008.7,3756705.5,13226074.1,3756832.6,13226126.7,3756928.5,13226157.8,3756978.9,13226207.9,3757049.7,13226246.4,3757096.9,13226304.2,3757154.5,13226327.0,3757183.1,13226333.4,3757210.6;";
        List<String> mocatorList = parseJeo(geo);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < mocatorList.size(); i++) {
            String[] coordinate = mocatorList.get(i).split("\\#");
            Map<String, Double> location = convertMC2LL(Double.parseDouble(coordinate[0]), Double.parseDouble(coordinate[1]));
            Double lng = location.get("lng");
            Double lat = location.get("lat");
            String coord = lng + "," + lat;
            sb.append(coord);
            if (i < mocatorList.size() - 1) {
                sb.append(";");
            }
        }
        String s = dealGeometry(sb.toString());
        System.out.println(s);
    }


    public static String getGeometryByStr(String geo) {
        List<String> mocatorList = parseJeo(geo);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < mocatorList.size(); i++) {
            String[] coordinate = mocatorList.get(i).split("\\#");
            Map<String, Double> location = convertMC2LL(Double.parseDouble(coordinate[0]), Double.parseDouble(coordinate[1]));
            Double lng = location.get("lng");
            Double lat = location.get("lat");
            String coord = lng + "," + lat;
            sb.append(coord);
            if (i < mocatorList.size() - 1) {
                sb.append(";");
            }
        }
        return dealGeometry(sb.toString());
    }

    private static String dealGeometry(String wkbGeometry) {
        String prefix = "MULTIPOLYGON(((";
        String postfix = ")))";
        String joinStr = ";";
        String[] pointArr = wkbGeometry.replace(prefix, "").replace(postfix, "").split(joinStr);
        List<String> pointStrList = new ArrayList<>();
        for (String point : pointArr) {
            String[] sourcePoint = point.split(",");

            Map<String, Double> transform5Result = CoordinateTransferUtils.bd09ToGcj02(Double.valueOf(sourcePoint[0]), Double.valueOf(sourcePoint[1]));
            String lonGc = MapUtil.getStr(transform5Result, "lon");
            String latGc = MapUtil.getStr(transform5Result, "lat");

            Map<String, Double> wgs84 = CoordinateTransferUtils.gcj02ToWgs84(Double.valueOf(lonGc),Double.valueOf(latGc));
            String lon = MapUtil.getStr(wgs84, "lon");
            String lat = MapUtil.getStr(wgs84, "lat");

            pointStrList.add(lon + " " + lat);
        }
        return pointStrList.stream().collect(Collectors.joining(",", prefix, postfix));
    }

    /**
     * 解析Jeo数据
     *
     * @param mocator
     */
    public static List<String> parseJeo(String mocator) {
        List<String> mocatorList = new ArrayList<String>();

        if (null == mocator) return null;
        /* 拆分数据 */
        String[] geos = mocator.split("\\|");
        int n = Integer.parseInt(geos[0]);
        String center = geos[1];
        String polylineMoca = geos[2]; //墨卡托坐标
        String[] plm = polylineMoca.split("\\;");

        /* 获取墨卡托边界 */
        String geo = null;
        if (n == 4) {
            for (int i = 0; i < plm.length; i++) {
                String[] geoPaths = plm[i].split("\\-");
                if (geoPaths[0].equals("1")) {
                    geo = geoPaths[1];
                }
            }
        }
        // 墨卡托坐标解析
        String[] geoPolyline = geo.split("\\,");
        for (int i = 0; i < geoPolyline.length; i += 2) {
            mocatorList.add(geoPolyline[i] + "#" + geoPolyline[i + 1]);
        }

        return mocatorList;
    }

    /**
     * 墨卡托坐标转经纬度坐标
     *
     * @param x
     * @param y
     * @return
     */
    public static Map<String, Double> convertMC2LL(Double x, Double y) {
        Double[] cF = null;
        x = Math.abs(x);
        y = Math.abs(y);
        for (int cE = 0; cE < MCBAND.length; cE++) {
            if (y >= MCBAND[cE]) {
                cF = MC2LL[cE];
                break;
            }
        }
        Map<String, Double> location = converter(x, y, cF);
        location.put("lng", location.get("x"));
        location.remove("x");
        location.put("lat", location.get("y"));
        location.remove("y");
        return location;
    }

    /**
     * 经纬度坐标转墨卡托坐标
     *
     * @param lng
     * @param lat
     * @return
     */
    private static Map<String, Double> convertLL2MC(Double lng, Double lat) {
        Double[] cE = null;
        lng = getLoop(lng, -180, 180);
        lat = getRange(lat, -74, 74);
        for (int i = 0; i < LLBAND.length; i++) {
            if (lat >= LLBAND[i]) {
                cE = LL2MC[i];
                break;
            }
        }
        if (cE != null) {
            for (int i = LLBAND.length - 1; i >= 0; i--) {
                if (lat <= -LLBAND[i]) {
                    cE = LL2MC[i];
                    break;
                }
            }
        }
        return converter(lng, lat, cE);
    }

    private static Map<String, Double> converter(Double x, Double y, Double[] cE) {
        Double xTemp = cE[0] + cE[1] * Math.abs(x);
        Double cC = Math.abs(y) / cE[9];
        Double yTemp = cE[2] + cE[3] * cC + cE[4] * cC * cC + cE[5] * cC * cC * cC + cE[6] * cC * cC * cC * cC + cE[7] * cC * cC * cC * cC * cC + cE[8] * cC * cC * cC * cC * cC * cC;
        xTemp *= (x < 0 ? -1 : 1);
        yTemp *= (y < 0 ? -1 : 1);
        Map<String, Double> location = new HashMap<String, Double>();
        location.put("x", xTemp);
        location.put("y", yTemp);
        return location;
    }

    private static Double getLoop(Double lng, Integer min, Integer max) {
        while (lng > max) {
            lng -= max - min;
        }
        while (lng < min) {
            lng += max - min;
        }
        return lng;
    }

    private static Double getRange(Double lat, Integer min, Integer max) {
        if (min != null) {
            lat = Math.max(lat, min);
        }
        if (max != null) {
            lat = Math.min(lat, max);
        }
        return lat;
    }

}
